#include <stdio.h>
#include <stdlib.h>

#include "TConstructor.h"
#include "TParser.h"
#include "funcionesAuxiliares.h"

/* Funcion callback que llama a evento ocurrido del Constructor
   se agrega porque no se podia setear directamente el puntero
   a la primitiva Tconstructor_eventoOcurrido ya que la firme es
   distinta(el primer parametro es TConstructo* y no void*
   No me convence esto si lo podemos mejorar joya */
int funcionCallback(const void* contexto, int evento, const void* dato){
    TConstructor* constructor = (TConstructor*)contexto;
    return Tconstructor_eventoOcurrido((void*)constructor, evento, (void*)dato);
}

int procesarListaCampos(TListaSimpleOrdenada* listaCampos){
    /* Contador de campos */
    int contador;
    /* Valor de la lista */
    char valor[MAX_DATO];
    /*defino otro valor para comparar*/
    char valor2[MAX_DATO];
    /* Se inicializa el contador en cero */
    contador = 0;
    /*suponiendo que se termino de armar la lista ordenada, sigo*/
    /*muevo el corriente al primero*/
    lso_MoverCorriente(listaCampos,LS_PRIMERO);
    /*obtengo el primer elemento*/
    lso_ElemCorriente(*listaCampos,valor);
    /*cuento el primer elemento*/
    contador++;
    while(lso_MoverCorriente(listaCampos,LS_SIGUIENTE)==0){  /*si estaba en el ultimo elemento devuelve false*/
        lso_ElemCorriente(*listaCampos,valor2);
        if(strcmp(valor,valor2)==0){
            contador++;
        }
        else{
            /*imprimo por pantalla, si contador mayor que 1*/
            if(contador>1){
                printf("%s: %i\n",valor,contador);
            }
            /*a tc->valor le copio valor2*/
            strcpy(valor,valor2);
            /*pongo el contador en 1 devuelta*/
            contador=1;
        }
    }
    /*imprimo el ultimo nombre con el ultimo contador que quedo, si contador mayor que 1*/
    if(contador>1){
        printf("%s: %i\n",valor,contador);
    }
    /* Retorna codigo de exito */
    return EXIT_SUCCESS;
}

int abrirProcesarArchivo(char* nombreArchivo){
    /*defino e inicializo las variables para manejar los errores*/
    char mensaje[MAX_DATO];
    int codigo = CODIGO_OK;
    /* Archivo a procesar */
    FILE* archivoProcesar;
    /* Constructor que se usa */
    TConstructor constructor;
    /* Parser que se usa */
    TParser parser;
    /* Lista de campos que se genera desde el constructor */
    TListaSimpleOrdenada listaCampos;
    /* Abre el archivo a procesar */
    archivoProcesar = fopen(nombreArchivo, "r");
    /* Se crea el constructor */
    Tconstructor_Crear(&constructor);
    /* Se crea el parser */
    TParser_Crear(&parser);
    /* Se seta la funcion callback al Parser */
    TParser_setCallback(&parser, 0, &constructor, &funcionCallback);
    /* Determina si se pudo abrir o no el archivo */
    if (archivoProcesar!=NULL){
        /* Si pudo abrir el archivo lo procesa */
        /* Mientras no se termine el archivo lo muestra linea por linea */
        while(!feof(archivoProcesar)&&(!codigo)){ /*si ya hubo un error deja de procesar el archivo*/
            /* Linea obtenida del archivo */
            char lineaArchivo[MAX_LONGITUD_LINEA];
            /* Posicion linea a procesar */
            int posicionLinea;
            /* Muestra el archivo linea a linea */
            fgets(lineaArchivo, MAX_LONGITUD_LINEA, archivoProcesar);
             /* Recorre caracter por caracter la linea leida */
            for (posicionLinea=0; posicionLinea<MAX_LONGITUD_LINEA && (lineaArchivo[posicionLinea]!=CARACTER_FIN_LINEA) && (lineaArchivo[posicionLinea]!='\0'); posicionLinea++){
                if (TParser_PushChar(&parser, lineaArchivo[posicionLinea])){
                	/*recuperarMensajeError(parser.codigoUltimoError);*/
                	TParser_getUltimoError(&parser, &codigo, mensaje);
                	printf("%s\n",mensaje);
                	TParser_terminarFlujo(&parser);
                	/* Cierra el archivo */
                	fclose(archivoProcesar);
                	return CODIGO_OK;
                }
            }
        }
        /* Crea la lista de Campos desde el constructor */
        lso_Crear(&listaCampos, 256*sizeof(char), &comparadorString);
        /*armo la lista de usuarios e imprimo por pantalla*/
        Tconstructor_ArmarLista(&constructor, &listaCampos);
        /* Se muestan los resultados de la lista de campos */
        procesarListaCampos(&listaCampos);
        /* Se termina el flujo del parser */
        TParser_terminarFlujo(&parser);
        /* Se destruye el Constructor */
        Tconstructor_Destruir(&constructor);
        /*libero los recursos de la lista de campos */
        lso_Vaciar(&listaCampos);
        /* Cierra el archivo */
        fclose(archivoProcesar);
    }else{
        /* Si no se encontro el archivo devuelve error */
        return CODIGO_ERROR_ARCHIVO_INEXISTENTE;
    }
    /* Si no ocurrio error, retorna ejecucion ok */
    return CODIGO_OK;
}

int main(int argc, char* argv[]){
    /* Determina que la cantidad de argumentos sea la correcta */
    if (argc==CANTIDAD_ARGUMENTOS_NECESARIOS){
        /* Codigo retorno procesado archivo */
        int codigoRetornoProcesadoArchivo = CODIGO_OK;
        /* Procesa el archivo indicado en el argumento */
        codigoRetornoProcesadoArchivo = abrirProcesarArchivo(argv[POSICION_ARGUMENTO_NOMBRE_ARCHIVO]);
        /* Si se produjo error muestra el mensaje correspondiente */
        if (codigoRetornoProcesadoArchivo!=CODIGO_OK){
            printf("%s\n",MENSAJE_ARCHIVO_INEXISTENTE);
        }
    }else{
        /* Muestra mensaje de error indicando que no se
           recibieron la cantidad de argumentos necesarios */
        printf( "%s",MENSAJE_CANTIDAD_ARGUMENTOS_INVALIDA);
    }
    /* Devuelve codigo de ejecucion correcta */
    return CODIGO_OK;
}
